{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "executionInfo": {
     "elapsed": 15,
     "status": "ok",
     "timestamp": 1649956709278,
     "user": {
      "displayName": "Sam Lu",
      "userId": "15789059763790170725"
     },
     "user_tz": -480
    },
    "id": "ILir9xpUCpU6"
   },
   "outputs": [],
   "source": [
    "import random\n",
    "import gym\n",
    "import numpy as np\n",
    "from tqdm import tqdm\n",
    "import torch\n",
    "import torch.nn.functional as F\n",
    "from torch.distributions import Normal\n",
    "import matplotlib.pyplot as plt\n",
    "import rl_utils"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "executionInfo": {
     "elapsed": 15,
     "status": "ok",
     "timestamp": 1649956709279,
     "user": {
      "displayName": "Sam Lu",
      "userId": "15789059763790170725"
     },
     "user_tz": -480
    },
    "id": "LDPkl2O-CpU9"
   },
   "outputs": [],
   "source": [
    "class PolicyNetContinuous(torch.nn.Module):\n",
    "    def __init__(self, state_dim, hidden_dim, action_dim, action_bound):\n",
    "        super(PolicyNetContinuous, self).__init__()\n",
    "        self.fc1 = torch.nn.Linear(state_dim, hidden_dim)\n",
    "        self.fc_mu = torch.nn.Linear(hidden_dim, action_dim)\n",
    "        self.fc_std = torch.nn.Linear(hidden_dim, action_dim)\n",
    "        self.action_bound = action_bound\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = F.relu(self.fc1(x))\n",
    "        mu = self.fc_mu(x)\n",
    "        std = F.softplus(self.fc_std(x))\n",
    "        dist = Normal(mu, std)\n",
    "        normal_sample = dist.rsample()  # rsample()是重参数化采样\n",
    "        log_prob = dist.log_prob(normal_sample)\n",
    "        action = torch.tanh(normal_sample)\n",
    "        # 计算tanh_normal分布的对数概率密度\n",
    "        log_prob = log_prob - torch.log(1 - torch.tanh(action).pow(2) + 1e-7)\n",
    "        action = action * self.action_bound\n",
    "        return action, log_prob\n",
    "\n",
    "\n",
    "class QValueNetContinuous(torch.nn.Module):\n",
    "    def __init__(self, state_dim, hidden_dim, action_dim):\n",
    "        super(QValueNetContinuous, self).__init__()\n",
    "        self.fc1 = torch.nn.Linear(state_dim + action_dim, hidden_dim)\n",
    "        self.fc2 = torch.nn.Linear(hidden_dim, hidden_dim)\n",
    "        self.fc_out = torch.nn.Linear(hidden_dim, 1)\n",
    "\n",
    "    def forward(self, x, a):\n",
    "        cat = torch.cat([x, a], dim=1)\n",
    "        x = F.relu(self.fc1(cat))\n",
    "        x = F.relu(self.fc2(x))\n",
    "        return self.fc_out(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "executionInfo": {
     "elapsed": 14,
     "status": "ok",
     "timestamp": 1649956709279,
     "user": {
      "displayName": "Sam Lu",
      "userId": "15789059763790170725"
     },
     "user_tz": -480
    },
    "id": "qwnXwWyzCpU-"
   },
   "outputs": [],
   "source": [
    "class SACContinuous:\n",
    "    ''' 处理连续动作的SAC算法 '''\n",
    "    def __init__(self, state_dim, hidden_dim, action_dim, action_bound,\n",
    "                 actor_lr, critic_lr, alpha_lr, target_entropy, tau, gamma,\n",
    "                 device):\n",
    "        self.actor = PolicyNetContinuous(state_dim, hidden_dim, action_dim,\n",
    "                                         action_bound).to(device)  # 策略网络\n",
    "        self.critic_1 = QValueNetContinuous(state_dim, hidden_dim,\n",
    "                                            action_dim).to(device)  # 第一个Q网络\n",
    "        self.critic_2 = QValueNetContinuous(state_dim, hidden_dim,\n",
    "                                            action_dim).to(device)  # 第二个Q网络\n",
    "        self.target_critic_1 = QValueNetContinuous(state_dim,\n",
    "                                                   hidden_dim, action_dim).to(\n",
    "                                                       device)  # 第一个目标Q网络\n",
    "        self.target_critic_2 = QValueNetContinuous(state_dim,\n",
    "                                                   hidden_dim, action_dim).to(\n",
    "                                                       device)  # 第二个目标Q网络\n",
    "        # 令目标Q网络的初始参数和Q网络一样\n",
    "        self.target_critic_1.load_state_dict(self.critic_1.state_dict())\n",
    "        self.target_critic_2.load_state_dict(self.critic_2.state_dict())\n",
    "        self.actor_optimizer = torch.optim.Adam(self.actor.parameters(),\n",
    "                                                lr=actor_lr)\n",
    "        self.critic_1_optimizer = torch.optim.Adam(self.critic_1.parameters(),\n",
    "                                                   lr=critic_lr)\n",
    "        self.critic_2_optimizer = torch.optim.Adam(self.critic_2.parameters(),\n",
    "                                                   lr=critic_lr)\n",
    "        # 使用alpha的log值,可以使训练结果比较稳定\n",
    "        self.log_alpha = torch.tensor(np.log(0.01), dtype=torch.float)\n",
    "        self.log_alpha.requires_grad = True  # 可以对alpha求梯度\n",
    "        self.log_alpha_optimizer = torch.optim.Adam([self.log_alpha],\n",
    "                                                    lr=alpha_lr)\n",
    "        self.target_entropy = target_entropy  # 目标熵的大小\n",
    "        self.gamma = gamma\n",
    "        self.tau = tau\n",
    "        self.device = device\n",
    "\n",
    "    def take_action(self, state):\n",
    "        state = torch.tensor([state], dtype=torch.float).to(self.device)\n",
    "        action = self.actor(state)[0]\n",
    "        return [action.item()]\n",
    "\n",
    "    def calc_target(self, rewards, next_states, dones):  # 计算目标Q值\n",
    "        next_actions, log_prob = self.actor(next_states)\n",
    "        entropy = -log_prob\n",
    "        q1_value = self.target_critic_1(next_states, next_actions)\n",
    "        q2_value = self.target_critic_2(next_states, next_actions)\n",
    "        next_value = torch.min(q1_value,\n",
    "                               q2_value) + self.log_alpha.exp() * entropy\n",
    "        td_target = rewards + self.gamma * next_value * (1 - dones)\n",
    "        return td_target\n",
    "\n",
    "    def soft_update(self, net, target_net):\n",
    "        for param_target, param in zip(target_net.parameters(),\n",
    "                                       net.parameters()):\n",
    "            param_target.data.copy_(param_target.data * (1.0 - self.tau) +\n",
    "                                    param.data * self.tau)\n",
    "\n",
    "    def update(self, transition_dict):\n",
    "        states = torch.tensor(transition_dict['states'],\n",
    "                              dtype=torch.float).to(self.device)\n",
    "        actions = torch.tensor(transition_dict['actions'],\n",
    "                               dtype=torch.float).view(-1, 1).to(self.device)\n",
    "        rewards = torch.tensor(transition_dict['rewards'],\n",
    "                               dtype=torch.float).view(-1, 1).to(self.device)\n",
    "        next_states = torch.tensor(transition_dict['next_states'],\n",
    "                                   dtype=torch.float).to(self.device)\n",
    "        dones = torch.tensor(transition_dict['dones'],\n",
    "                             dtype=torch.float).view(-1, 1).to(self.device)\n",
    "        # 和之前章节一样,对倒立摆环境的奖励进行重塑以便训练\n",
    "        rewards = (rewards + 8.0) / 8.0\n",
    "\n",
    "        # 更新两个Q网络\n",
    "        td_target = self.calc_target(rewards, next_states, dones)\n",
    "        critic_1_loss = torch.mean(\n",
    "            F.mse_loss(self.critic_1(states, actions), td_target.detach()))\n",
    "        critic_2_loss = torch.mean(\n",
    "            F.mse_loss(self.critic_2(states, actions), td_target.detach()))\n",
    "        self.critic_1_optimizer.zero_grad()\n",
    "        critic_1_loss.backward()\n",
    "        self.critic_1_optimizer.step()\n",
    "        self.critic_2_optimizer.zero_grad()\n",
    "        critic_2_loss.backward()\n",
    "        self.critic_2_optimizer.step()\n",
    "\n",
    "        # 更新策略网络\n",
    "        new_actions, log_prob = self.actor(states)\n",
    "        entropy = -log_prob\n",
    "        q1_value = self.critic_1(states, new_actions)\n",
    "        q2_value = self.critic_2(states, new_actions)\n",
    "        actor_loss = torch.mean(-self.log_alpha.exp() * entropy -\n",
    "                                torch.min(q1_value, q2_value))\n",
    "        self.actor_optimizer.zero_grad()\n",
    "        actor_loss.backward()\n",
    "        self.actor_optimizer.step()\n",
    "\n",
    "        # 更新alpha值\n",
    "        alpha_loss = torch.mean(\n",
    "            (entropy - self.target_entropy).detach() * self.log_alpha.exp())\n",
    "        self.log_alpha_optimizer.zero_grad()\n",
    "        alpha_loss.backward()\n",
    "        self.log_alpha_optimizer.step()\n",
    "\n",
    "        self.soft_update(self.critic_1, self.target_critic_1)\n",
    "        self.soft_update(self.critic_2, self.target_critic_2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 141373,
     "status": "ok",
     "timestamp": 1649956709277,
     "user": {
      "displayName": "Sam Lu",
      "userId": "15789059763790170725"
     },
     "user_tz": -480
    },
    "id": "ICsfMCdmCpVA",
    "outputId": "70ff6ca1-6829-450b-a12f-76c79da63711"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Iteration 0:   0%|          | 0/10 [00:00<?, ?it/s]/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:27: UserWarning: Creating a tensor from a list of numpy.ndarrays is extremely slow. Please consider converting the list to a single numpy.ndarray with numpy.array() before converting to a tensor. (Triggered internally at  ../torch/csrc/utils/tensor_new.cpp:201.)\n",
      "Iteration 0: 100%|██████████| 10/10 [00:09<00:00,  1.03it/s, episode=10, return=-1534.655]\n",
      "Iteration 1: 100%|██████████| 10/10 [00:18<00:00,  1.83s/it, episode=20, return=-1085.715]\n",
      "Iteration 2: 100%|██████████| 10/10 [00:15<00:00,  1.60s/it, episode=30, return=-364.507]\n",
      "Iteration 3: 100%|██████████| 10/10 [00:13<00:00,  1.37s/it, episode=40, return=-222.485]\n",
      "Iteration 4: 100%|██████████| 10/10 [00:13<00:00,  1.36s/it, episode=50, return=-157.978]\n",
      "Iteration 5: 100%|██████████| 10/10 [00:13<00:00,  1.37s/it, episode=60, return=-166.056]\n",
      "Iteration 6: 100%|██████████| 10/10 [00:13<00:00,  1.38s/it, episode=70, return=-143.147]\n",
      "Iteration 7: 100%|██████████| 10/10 [00:13<00:00,  1.37s/it, episode=80, return=-127.939]\n",
      "Iteration 8: 100%|██████████| 10/10 [00:14<00:00,  1.42s/it, episode=90, return=-180.905]\n",
      "Iteration 9: 100%|██████████| 10/10 [00:14<00:00,  1.41s/it, episode=100, return=-171.265]\n"
     ]
    }
   ],
   "source": [
    "env_name = 'Pendulum-v0'\n",
    "env = gym.make(env_name)\n",
    "state_dim = env.observation_space.shape[0]\n",
    "action_dim = env.action_space.shape[0]\n",
    "action_bound = env.action_space.high[0]  # 动作最大值\n",
    "random.seed(0)\n",
    "np.random.seed(0)\n",
    "env.seed(0)\n",
    "torch.manual_seed(0)\n",
    "\n",
    "actor_lr = 3e-4\n",
    "critic_lr = 3e-3\n",
    "alpha_lr = 3e-4\n",
    "num_episodes = 100\n",
    "hidden_dim = 128\n",
    "gamma = 0.99\n",
    "tau = 0.005  # 软更新参数\n",
    "buffer_size = 100000\n",
    "minimal_size = 1000\n",
    "batch_size = 64\n",
    "target_entropy = -env.action_space.shape[0]\n",
    "device = torch.device(\"cuda\") if torch.cuda.is_available() else torch.device(\n",
    "    \"cpu\")\n",
    "\n",
    "replay_buffer = rl_utils.ReplayBuffer(buffer_size)\n",
    "agent = SACContinuous(state_dim, hidden_dim, action_dim, action_bound,\n",
    "                      actor_lr, critic_lr, alpha_lr, target_entropy, tau,\n",
    "                      gamma, device)\n",
    "\n",
    "return_list = rl_utils.train_off_policy_agent(env, agent, num_episodes,\n",
    "                                              replay_buffer, minimal_size,\n",
    "                                              batch_size)\n",
    "\n",
    "# Iteration 0: 100%|██████████| 10/10 [00:07<00:00,  1.35it/s, episode=10,\n",
    "# return=-1534.655]\n",
    "# Iteration 1: 100%|██████████| 10/10 [00:13<00:00,  1.32s/it, episode=20,\n",
    "# return=-1085.715]\n",
    "# Iteration 2: 100%|██████████| 10/10 [00:13<00:00,  1.38s/it, episode=30,\n",
    "# return=-377.923]\n",
    "# Iteration 3: 100%|██████████| 10/10 [00:13<00:00,  1.37s/it, episode=40,\n",
    "# return=-284.440]\n",
    "# Iteration 4: 100%|██████████| 10/10 [00:13<00:00,  1.36s/it, episode=50,\n",
    "# return=-183.556]\n",
    "# Iteration 5: 100%|██████████| 10/10 [00:14<00:00,  1.43s/it, episode=60,\n",
    "# return=-202.841]\n",
    "# Iteration 6: 100%|██████████| 10/10 [00:14<00:00,  1.41s/it, episode=70,\n",
    "# return=-193.436]\n",
    "# Iteration 7: 100%|██████████| 10/10 [00:14<00:00,  1.42s/it, episode=80,\n",
    "# return=-131.132]\n",
    "# Iteration 8: 100%|██████████| 10/10 [00:14<00:00,  1.41s/it, episode=90,\n",
    "# return=-181.888]\n",
    "# Iteration 9: 100%|██████████| 10/10 [00:14<00:00,  1.42s/it, episode=100,\n",
    "# return=-139.574]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 573
    },
    "executionInfo": {
     "elapsed": 1016,
     "status": "ok",
     "timestamp": 1649956710281,
     "user": {
      "displayName": "Sam Lu",
      "userId": "15789059763790170725"
     },
     "user_tz": -480
    },
    "id": "Y8oDpGATCpVB",
    "outputId": "c04d886a-7464-4957-c4f2-7b945f31d576"
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "episodes_list = list(range(len(return_list)))\n",
    "plt.plot(episodes_list, return_list)\n",
    "plt.xlabel('Episodes')\n",
    "plt.ylabel('Returns')\n",
    "plt.title('SAC on {}'.format(env_name))\n",
    "plt.show()\n",
    "\n",
    "mv_return = rl_utils.moving_average(return_list, 9)\n",
    "plt.plot(episodes_list, mv_return)\n",
    "plt.xlabel('Episodes')\n",
    "plt.ylabel('Returns')\n",
    "plt.title('SAC on {}'.format(env_name))\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "executionInfo": {
     "elapsed": 12,
     "status": "ok",
     "timestamp": 1649956710281,
     "user": {
      "displayName": "Sam Lu",
      "userId": "15789059763790170725"
     },
     "user_tz": -480
    },
    "id": "1K1yxT3kCpVC"
   },
   "outputs": [],
   "source": [
    "class PolicyNet(torch.nn.Module):\n",
    "    def __init__(self, state_dim, hidden_dim, action_dim):\n",
    "        super(PolicyNet, self).__init__()\n",
    "        self.fc1 = torch.nn.Linear(state_dim, hidden_dim)\n",
    "        self.fc2 = torch.nn.Linear(hidden_dim, action_dim)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = F.relu(self.fc1(x))\n",
    "        return F.softmax(self.fc2(x), dim=1)\n",
    "\n",
    "\n",
    "class QValueNet(torch.nn.Module):\n",
    "    ''' 只有一层隐藏层的Q网络 '''\n",
    "    def __init__(self, state_dim, hidden_dim, action_dim):\n",
    "        super(QValueNet, self).__init__()\n",
    "        self.fc1 = torch.nn.Linear(state_dim, hidden_dim)\n",
    "        self.fc2 = torch.nn.Linear(hidden_dim, action_dim)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = F.relu(self.fc1(x))\n",
    "        return self.fc2(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 58694,
     "status": "ok",
     "timestamp": 1649956768968,
     "user": {
      "displayName": "Sam Lu",
      "userId": "15789059763790170725"
     },
     "user_tz": -480
    },
    "id": "-uNc-_fuCpVC",
    "outputId": "6be626e7-a3a7-4945-ec7c-e634c1c23b8b"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Iteration 0: 100%|██████████| 20/20 [00:00<00:00, 148.74it/s, episode=20, return=19.700]\n",
      "Iteration 1: 100%|██████████| 20/20 [00:00<00:00, 28.35it/s, episode=40, return=10.600]\n",
      "Iteration 2: 100%|██████████| 20/20 [00:00<00:00, 24.96it/s, episode=60, return=10.000]\n",
      "Iteration 3: 100%|██████████| 20/20 [00:00<00:00, 24.87it/s, episode=80, return=9.800]\n",
      "Iteration 4: 100%|██████████| 20/20 [00:00<00:00, 26.33it/s, episode=100, return=9.100]\n",
      "Iteration 5: 100%|██████████| 20/20 [00:00<00:00, 26.30it/s, episode=120, return=9.500]\n",
      "Iteration 6: 100%|██████████| 20/20 [00:09<00:00,  2.19it/s, episode=140, return=178.400]\n",
      "Iteration 7: 100%|██████████| 20/20 [00:15<00:00,  1.30it/s, episode=160, return=200.000]\n",
      "Iteration 8: 100%|██████████| 20/20 [00:15<00:00,  1.30it/s, episode=180, return=200.000]\n",
      "Iteration 9: 100%|██████████| 20/20 [00:15<00:00,  1.29it/s, episode=200, return=197.600]\n"
     ]
    }
   ],
   "source": [
    "class SAC:\n",
    "    ''' 处理离散动作的SAC算法 '''\n",
    "    def __init__(self, state_dim, hidden_dim, action_dim, actor_lr, critic_lr,\n",
    "                 alpha_lr, target_entropy, tau, gamma, device):\n",
    "        # 策略网络\n",
    "        self.actor = PolicyNet(state_dim, hidden_dim, action_dim).to(device)\n",
    "        # 第一个Q网络\n",
    "        self.critic_1 = QValueNet(state_dim, hidden_dim, action_dim).to(device)\n",
    "        # 第二个Q网络\n",
    "        self.critic_2 = QValueNet(state_dim, hidden_dim, action_dim).to(device)\n",
    "        self.target_critic_1 = QValueNet(state_dim, hidden_dim,\n",
    "                                         action_dim).to(device)  # 第一个目标Q网络\n",
    "        self.target_critic_2 = QValueNet(state_dim, hidden_dim,\n",
    "                                         action_dim).to(device)  # 第二个目标Q网络\n",
    "        # 令目标Q网络的初始参数和Q网络一样\n",
    "        self.target_critic_1.load_state_dict(self.critic_1.state_dict())\n",
    "        self.target_critic_2.load_state_dict(self.critic_2.state_dict())\n",
    "        self.actor_optimizer = torch.optim.Adam(self.actor.parameters(),\n",
    "                                                lr=actor_lr)\n",
    "        self.critic_1_optimizer = torch.optim.Adam(self.critic_1.parameters(),\n",
    "                                                   lr=critic_lr)\n",
    "        self.critic_2_optimizer = torch.optim.Adam(self.critic_2.parameters(),\n",
    "                                                   lr=critic_lr)\n",
    "        # 使用alpha的log值,可以使训练结果比较稳定\n",
    "        self.log_alpha = torch.tensor(np.log(0.01), dtype=torch.float)\n",
    "        self.log_alpha.requires_grad = True  # 可以对alpha求梯度\n",
    "        self.log_alpha_optimizer = torch.optim.Adam([self.log_alpha],\n",
    "                                                    lr=alpha_lr)\n",
    "        self.target_entropy = target_entropy  # 目标熵的大小\n",
    "        self.gamma = gamma\n",
    "        self.tau = tau\n",
    "        self.device = device\n",
    "\n",
    "    def take_action(self, state):\n",
    "        state = torch.tensor([state], dtype=torch.float).to(self.device)\n",
    "        probs = self.actor(state)\n",
    "        action_dist = torch.distributions.Categorical(probs)\n",
    "        action = action_dist.sample()\n",
    "        return action.item()\n",
    "\n",
    "    # 计算目标Q值,直接用策略网络的输出概率进行期望计算\n",
    "    def calc_target(self, rewards, next_states, dones):\n",
    "        next_probs = self.actor(next_states)\n",
    "        next_log_probs = torch.log(next_probs + 1e-8)\n",
    "        entropy = -torch.sum(next_probs * next_log_probs, dim=1, keepdim=True)\n",
    "        q1_value = self.target_critic_1(next_states)\n",
    "        q2_value = self.target_critic_2(next_states)\n",
    "        min_qvalue = torch.sum(next_probs * torch.min(q1_value, q2_value),\n",
    "                               dim=1,\n",
    "                               keepdim=True)\n",
    "        next_value = min_qvalue + self.log_alpha.exp() * entropy\n",
    "        td_target = rewards + self.gamma * next_value * (1 - dones)\n",
    "        return td_target\n",
    "\n",
    "    def soft_update(self, net, target_net):\n",
    "        for param_target, param in zip(target_net.parameters(),\n",
    "                                       net.parameters()):\n",
    "            param_target.data.copy_(param_target.data * (1.0 - self.tau) +\n",
    "                                    param.data * self.tau)\n",
    "\n",
    "    def update(self, transition_dict):\n",
    "        states = torch.tensor(transition_dict['states'],\n",
    "                              dtype=torch.float).to(self.device)\n",
    "        actions = torch.tensor(transition_dict['actions']).view(-1, 1).to(\n",
    "            self.device)  # 动作不再是float类型\n",
    "        rewards = torch.tensor(transition_dict['rewards'],\n",
    "                               dtype=torch.float).view(-1, 1).to(self.device)\n",
    "        next_states = torch.tensor(transition_dict['next_states'],\n",
    "                                   dtype=torch.float).to(self.device)\n",
    "        dones = torch.tensor(transition_dict['dones'],\n",
    "                             dtype=torch.float).view(-1, 1).to(self.device)\n",
    "\n",
    "        # 更新两个Q网络\n",
    "        td_target = self.calc_target(rewards, next_states, dones)\n",
    "        critic_1_q_values = self.critic_1(states).gather(1, actions)\n",
    "        critic_1_loss = torch.mean(\n",
    "            F.mse_loss(critic_1_q_values, td_target.detach()))\n",
    "        critic_2_q_values = self.critic_2(states).gather(1, actions)\n",
    "        critic_2_loss = torch.mean(\n",
    "            F.mse_loss(critic_2_q_values, td_target.detach()))\n",
    "        self.critic_1_optimizer.zero_grad()\n",
    "        critic_1_loss.backward()\n",
    "        self.critic_1_optimizer.step()\n",
    "        self.critic_2_optimizer.zero_grad()\n",
    "        critic_2_loss.backward()\n",
    "        self.critic_2_optimizer.step()\n",
    "\n",
    "        # 更新策略网络\n",
    "        probs = self.actor(states)\n",
    "        log_probs = torch.log(probs + 1e-8)\n",
    "        # 直接根据概率计算熵\n",
    "        entropy = -torch.sum(probs * log_probs, dim=1, keepdim=True)  #\n",
    "        q1_value = self.critic_1(states)\n",
    "        q2_value = self.critic_2(states)\n",
    "        min_qvalue = torch.sum(probs * torch.min(q1_value, q2_value),\n",
    "                               dim=1,\n",
    "                               keepdim=True)  # 直接根据概率计算期望\n",
    "        actor_loss = torch.mean(-self.log_alpha.exp() * entropy - min_qvalue)\n",
    "        self.actor_optimizer.zero_grad()\n",
    "        actor_loss.backward()\n",
    "        self.actor_optimizer.step()\n",
    "\n",
    "        # 更新alpha值\n",
    "        alpha_loss = torch.mean(\n",
    "            (entropy - target_entropy).detach() * self.log_alpha.exp())\n",
    "        self.log_alpha_optimizer.zero_grad()\n",
    "        alpha_loss.backward()\n",
    "        self.log_alpha_optimizer.step()\n",
    "\n",
    "        self.soft_update(self.critic_1, self.target_critic_1)\n",
    "        self.soft_update(self.critic_2, self.target_critic_2)\n",
    "\n",
    "\n",
    "actor_lr = 1e-3\n",
    "critic_lr = 1e-2\n",
    "alpha_lr = 1e-2\n",
    "num_episodes = 200\n",
    "hidden_dim = 128\n",
    "gamma = 0.98\n",
    "tau = 0.005  # 软更新参数\n",
    "buffer_size = 10000\n",
    "minimal_size = 500\n",
    "batch_size = 64\n",
    "target_entropy = -1\n",
    "device = torch.device(\"cuda\") if torch.cuda.is_available() else torch.device(\n",
    "    \"cpu\")\n",
    "\n",
    "env_name = 'CartPole-v0'\n",
    "env = gym.make(env_name)\n",
    "random.seed(0)\n",
    "np.random.seed(0)\n",
    "env.seed(0)\n",
    "torch.manual_seed(0)\n",
    "replay_buffer = rl_utils.ReplayBuffer(buffer_size)\n",
    "state_dim = env.observation_space.shape[0]\n",
    "action_dim = env.action_space.n\n",
    "agent = SAC(state_dim, hidden_dim, action_dim, actor_lr, critic_lr, alpha_lr,\n",
    "            target_entropy, tau, gamma, device)\n",
    "\n",
    "return_list = rl_utils.train_off_policy_agent(env, agent, num_episodes,\n",
    "                                              replay_buffer, minimal_size,\n",
    "                                              batch_size)\n",
    "\n",
    "# Iteration 0: 100%|██████████| 20/20 [00:00<00:00, 193.82it/s, episode=20,\n",
    "# return=19.700]\n",
    "# Iteration 1: 100%|██████████| 20/20 [00:00<00:00, 29.39it/s, episode=40,\n",
    "# return=10.600]\n",
    "# Iteration 2: 100%|██████████| 20/20 [00:00<00:00, 26.38it/s, episode=60,\n",
    "# return=10.000]\n",
    "# Iteration 3: 100%|██████████| 20/20 [00:00<00:00, 24.32it/s, episode=80,\n",
    "# return=9.800]\n",
    "# Iteration 4: 100%|██████████| 20/20 [00:00<00:00, 26.86it/s, episode=100,\n",
    "# return=9.100]\n",
    "# Iteration 5: 100%|██████████| 20/20 [00:00<00:00, 26.87it/s, episode=120,\n",
    "# return=9.500]\n",
    "# Iteration 6: 100%|██████████| 20/20 [00:07<00:00,  2.64it/s, episode=140,\n",
    "# return=178.400]\n",
    "# Iteration 7: 100%|██████████| 20/20 [00:15<00:00,  1.33it/s, episode=160,\n",
    "# return=200.000]\n",
    "# Iteration 8: 100%|██████████| 20/20 [00:15<00:00,  1.31it/s, episode=180,\n",
    "# return=200.000]\n",
    "# Iteration 9: 100%|██████████| 20/20 [00:15<00:00,  1.32it/s, episode=200,\n",
    "# return=197.600]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 573
    },
    "executionInfo": {
     "elapsed": 852,
     "status": "ok",
     "timestamp": 1649956769816,
     "user": {
      "displayName": "Sam Lu",
      "userId": "15789059763790170725"
     },
     "user_tz": -480
    },
    "id": "O2ERWxblCpVF",
    "outputId": "0e3c08cc-0221-425f-86ec-5c41fb2b533c"
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "episodes_list = list(range(len(return_list)))\n",
    "plt.plot(episodes_list, return_list)\n",
    "plt.xlabel('Episodes')\n",
    "plt.ylabel('Returns')\n",
    "plt.title('SAC on {}'.format(env_name))\n",
    "plt.show()\n",
    "\n",
    "mv_return = rl_utils.moving_average(return_list, 9)\n",
    "plt.plot(episodes_list, mv_return)\n",
    "plt.xlabel('Episodes')\n",
    "plt.ylabel('Returns')\n",
    "plt.title('SAC on {}'.format(env_name))\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [],
   "name": "第14章-SAC算法.ipynb",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
